/**
 * 封装 fetch
 * 参考文献：https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
 */
import qs from "qs";

// 配置不同环境的 baseUrl 地址
const mapBaseUrl = {
  development: "http://127.0.0.1",
  production: "http://www.online.com",
  test: "http://192.168.162.65",
};
const baseUrl = mapBaseUrl[process.env.NODE_ENV];

function request(url, options = {}) {
  url = baseUrl + url;
  // 处理 GET 请求
  !options.method ? (options.method = "GET") : null;
  if (options.hasOwnProperty("params")) {
    if (/^(GET|DELETE|HEAD|OPTIONS)$/i.test(options.method)) {
      const ask = url.includes("?") ? "&" : "?";
      url += `${ask}${qs.stringify(options.params)}`;
    }
    delete options.params;
  }

  // 合并配置项
  options = Object.assign({
    // 允许跨域携带凭证
    credentials: "include",
    // 设置请求头
    headers: {},
  });

  // 校验 TOKEN
  const token = localStorage.getItem("token");
  token && (options.headers.Authorization = token);

  // 处理 POST 请求
  if (/^(POST|PUT)$/i.test(options.method)) {
    !options.type ? (options.type = "urlencoded") : null;
    if (options.type === "urlencoded") {
      options.headers["Content-Type"] = "application/x-www-form-urlencoded";
      options.body = qs.stringify(options.body);
    }
    if (options.type === "json") {
      options.headers["Content-Type"] = "application/json";
      options.body = qs.stringify(options.body);
    }
  }

  // fetch 只要服务器有返回，fetch 就会走 then 方法，服务器没有响应，走catch
  // axios 服务器返回 2xx 状态码时，才走then，其他状态码和状态走catch
  return fetch(url, options)
    .then((response) => {
      // 返回的结果可能是非200状态码
      if (!/^(2|3)\d{2}$/.test(response.status)) {
        switch (response.status) {
          case 401:
            // 需要验证用户，重新登录，跳转到登录页
            break;
          case 403:
            // 服务器接收到请求，拒绝执行，TOKEN 过期
            localStorage.removeItem("token");
            break;
          case 404:
            // 请求地址不存在，接口不存在
            break;
          default:
            break;
        }
        return Promise.reject(response);
      }
      return response.json();
    })
    .catch((error) => {
      if (!window.navigator.onLine) {
        // 断网处理(跳转至断网页面，弹窗提示)
        return;
      }
      return Promise.reject(error);
    });
}

export default request;
